(defun range (start end)
  (loop for i from start to end collect i)) 

(defun list-divisors (n)
  (loop for i from 1 to (sqrt n)
        when (= (mod n i) 0)
        collect i
        and collect (/ n i)))

(defun sum-of-restricted-divisors (n)
  (- (reduce #'+ (remove-duplicates (list-divisors n))) n))

;;; whether n is an abundatnt number
(defun abundant-number-p (n)
  (> (sum-of-restricted-divisors n) n))

(defun abundant-number-list (&key (upper-limit 10) (test 'abundant-number-p))
  (loop for i from 12 to upper-limit
        when (funcall test i)
        collect i))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defun find-divisors (x)
  (let ((divs nil))
    (loop for i from 1 to (sqrt x) 
       do (when (zerop (mod x i)) 
	    (push i divs)
	    (let ((d (/ x i)))
	      (unless (or (= i 1) (= i d))
		(push d divs)))))
    divs))
 
(defun abundant-p (x)
  (> (reduce #'+ (find-divisors x)) x))

(defun p23 (&optional (size 28))
  (let ((sums-of-abundants (make-array size :element-type 'bit))
	(abundants nil))
    (loop for i from 0 to size
	 do (when (abundant-p i)
	      (setq abundants (append abundants (list i)))
	      (loop for j in abundants
		 while (< (+ i j) size)
		 do (setf (elt sums-of-abundants (+ i j)) 1))))
    (loop for i from 0 below size
	 when (zerop (elt sums-of-abundants i))
	 sum i)))

(format t "~a~%" (time (p23)))
(print (abundant-number-list :upper-limit 28))
(print (length (abundant-number-list :upper-limit 140 :test 'abundant-p)))
